package com.dj.mingkong.common.infrastructure.base.repository;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dj.mingkong.common.constant.CommonConstants;
import com.dj.mingkong.common.exception.ExceptionCode;
import com.dj.mingkong.common.exception.ExceptionFactory;
import com.dj.mingkong.common.infrastructure.base.dto.query.QueryVo;
import com.dj.mingkong.common.infrastructure.base.eo.BaseEo;
import com.dj.mingkong.common.util.AssertUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ReflectionUtils;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

/**
 * @author zenglonghui
 * @date: 2022/5/17 17:29
 */
public abstract class BaseDatabaseRepository<M extends BaseMapper<T>, T extends BaseEo, Q extends QueryVo> extends ServiceImpl<M, T> {
    private static final int IN_SIZE = 1000;

    public BaseDatabaseRepository() {
    }

    public void updateAllColumnById(T entity) {
        UpdateWrapper<T> updateWrapper = Wrappers.update();
        TableInfo tableInfo = TableInfoHelper.getTableInfo(entity.getClass());
        List<TableFieldInfo> fieldList = tableInfo.getFieldList();
        Iterator var5 = fieldList.iterator();

        while (var5.hasNext()) {
            TableFieldInfo fieldInfo = (TableFieldInfo) var5.next();
            String column = fieldInfo.getColumn();
            String property = fieldInfo.getProperty();
            Field field = ReflectionUtils.findField(entity.getClass(), property);
            if (field != null && !this.ignoreDevopsFields(property)) {
                field.setAccessible(true);
                Object value = ReflectionUtils.getField(field, entity);
                updateWrapper.set(column, value);
            }
        }

        String primaryKeyProperty = tableInfo.getKeyProperty();
        Field field = ReflectionUtils.findField(entity.getClass(), primaryKeyProperty);
        if (field == null) {
            throw ExceptionFactory.bizException(tableInfo.getTableName() + "缺失主键");
        } else {
            field.setAccessible(true);
            Object primaryKeyValue = ReflectionUtils.getField(field, entity);
            updateWrapper.eq(tableInfo.getKeyColumn(), primaryKeyValue);
            this.update(entity, updateWrapper);
        }
    }

    protected boolean ignoreDevopsFields(String property) {
        return "createPerson".equalsIgnoreCase(property) || "createTime".equalsIgnoreCase(property) || "updateTime".equalsIgnoreCase(property);
    }

    public boolean deleteById(Serializable id) {
        int affCnt = this.baseMapper.deleteById(id);
        return affCnt > 0;
    }

    public void deleteByIds(Collection<? extends Serializable> idList) {
        if (CollectionUtils.isEmpty(idList)) {
            this.log.warn("idList集合为空");
        } else {
            this.baseMapper.deleteBatchIds(idList);
        }
    }

    public boolean delete(Wrapper<T> qw) {
        int affCnt = this.baseMapper.delete(qw);
        return affCnt > 0;
    }

    public <E extends T> boolean delete(E query) {
        int affCnt = this.baseMapper.delete(this.checkQueryEo(query));
        return affCnt > 0;
    }

    public <E extends T> T getOne(E query) {
        return this.getOne(this.checkQueryEo(query));
    }

    @Override
    public T getOne(Wrapper<T> qw) {
        Page<T> p = new Page(1L, 2L);
        p.setSearchCount(Boolean.FALSE);
        IPage<T> page = this.baseMapper.selectPage(p, qw);
        if (page.getRecords().isEmpty()) {
            return null;
        } else {
            int size = page.getRecords().size();
            if (size > 1) {
                this.log.warn("getOne查询到多条记录,只返回第一条");
            }

            return (T) page.getRecords().get(0);
        }
    }

    public <E extends T> Boolean exist(E query) {
        return this.exist(this.checkQueryEo(query));
    }

    public Boolean exist(Wrapper<T> qw) {
        Page<T> p = new Page(1L, 1L);
        p.setSearchCount(Boolean.FALSE);
        IPage<T> page = this.baseMapper.selectPage(p, qw);
        return page.getRecords().isEmpty() ? Boolean.FALSE : Boolean.TRUE;
    }

    public T getRequired(Serializable id) {
        T obj = (T) this.baseMapper.selectById(id);
        AssertUtils.isNotNull(obj, ExceptionCode.NO_DATA.getMessage(), new Object[0]);
        return obj;
    }

    public <E extends T> int count(E query) {
        return (int) this.count(this.buildQuery(query));
    }

    public <E extends T> List<T> list(E t, int pageNum, int pageSize) {
        if (pageNum < 1 || pageSize < 1) {
            pageNum = CommonConstants.DEFAULT_PAGE_NUM;
            pageSize = CommonConstants.DEFAULT_PAGE_SIZE;
        }

        return this.list(this.buildQuery(t), pageNum, pageSize);
    }

    public List<T> list(Wrapper<T> qw, int pageNum, int pageSize) {
        if (pageNum < 1 || pageSize < 1) {
            pageNum = CommonConstants.DEFAULT_PAGE_NUM;
            pageSize = CommonConstants.DEFAULT_PAGE_SIZE;
        }

        Page<T> p = new Page((long) pageNum, (long) pageSize);
        p.setSearchCount(Boolean.FALSE);
        return ((Page) this.baseMapper.selectPage(p, qw)).getRecords();
    }

    public <E extends T> Page<T> listPage(E query, int currentPage, int pageSize) {
        if (currentPage < 1 || pageSize < 1) {
            currentPage = CommonConstants.DEFAULT_PAGE_NUM;
            pageSize = CommonConstants.DEFAULT_PAGE_SIZE;
        }

        return this.listPage(this.buildQuery(query), currentPage, pageSize);
    }

    public Page<T> listPage(Wrapper<T> qw, int currentPage, int pageSize) {
        if (currentPage < 1 || pageSize < 1) {
            currentPage = CommonConstants.DEFAULT_PAGE_NUM;
            pageSize = CommonConstants.DEFAULT_PAGE_SIZE;
        }

        Page<T> p = new Page((long) currentPage, (long) pageSize);
        return (Page) this.baseMapper.selectPage(p, qw);
    }

    public <E extends T> List<T> listAll(E query) {
        return this.listAll(this.buildQuery(query));
    }

    public List<T> listAll(Wrapper<T> ew) {
        return this.baseMapper.selectList(ew);
    }

    public M getMapper() {
        return this.baseMapper;
    }

    private Wrapper<T> checkQueryEo(T t) {
        Wrapper<T> tWrapper = this.buildQuery(t);
        AssertUtils.isNotNull(tWrapper, "查询条件不能为空", new Object[0]);
        return tWrapper;
    }

    protected <E extends T> Wrapper<T> buildQuery(E e) {
        return null;
    }
}
